package com.ebspp.client.watcher;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.thrift.TException;

import com.ebspp.client.serverManager.ServerManager;
import com.ebspp.global.General;
import com.ebspp.thrift.DataMsg;
import com.ebspp.thrift.Identity;
import com.ebspp.thrift.ResourceType;

public class WatchManager 
{
	private static boolean init = false;
	private static Map<Identity, Map<ResourceType, WatchBuffer>> watchBufMap;
	private static Map<Integer, Set<String>> bufServerMap;
	public synchronized static void initWatch()
	{
		if(init)
			return;
		bufServerMap = Collections.synchronizedMap(new HashMap<Integer, Set<String>>());
		watchBufMap = Collections.synchronizedMap(new HashMap<Identity, Map<ResourceType, WatchBuffer>>());
		new Thread(new Runnable(){

			@Override
			public void run() {
				// TODO Auto-generated method stub
				WatchServer.initServer();
			}
		}, "watch Thread").start();
		
		init = true;
	}
	public static boolean isInit()
	{
		return init;
	}
	
	public static boolean watch(List<String> servers, ResourceType resType, Identity wID)
	{	
		Map<ResourceType, WatchBuffer> resBufMap = watchBufMap.get(wID);
		if(resBufMap == null)
		{
			resBufMap = Collections.synchronizedMap(new HashMap<ResourceType, WatchBuffer>());
			watchBufMap.put(wID, resBufMap);
		}
		WatchBuffer buf = resBufMap.get(resType);
		if(buf == null)
		{
			buf = new WatchBuffer(General.maxWaBufSize, resType, wID);
			resBufMap.put(resType, buf);
			
			Set<String> watchedServers = new HashSet<String>();
			bufServerMap.put(buf.getBufID(), watchedServers);
		}
		Set<String> watchedServers = bufServerMap.get(buf.getBufID());
		for(String server : servers)
			watchedServers.add(server);
		
		boolean watched = true;
		for(String server : servers)
		{
			try 
			{
				if(!ServerManager.watch(server, resType, wID))
				{
					watched = false;
					break;
				}
			} catch (TException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				watched = false;
				break;
			}
		}
		
		if(!watched)
		{
			for(String server : servers)
				ServerManager.deWatch(server, resType, wID);
			
			buf.close();
			resBufMap.remove(resType);
			if(resBufMap.size() == 0)
				watchBufMap.remove(wID);
		}
		return watched;
	}
	
	
	public static boolean deWatch(String server, ResourceType resType, Identity wID)
	{
		boolean deWatch = ServerManager.deWatch(server, resType, wID);
		if(deWatch)
		{
			Map<ResourceType, WatchBuffer> resBufMap = watchBufMap.get(wID);
			WatchBuffer buf = resBufMap.get(resType);
			Set<String> watchedServers = bufServerMap.get(buf.getBufID());
			watchedServers.remove(server);
			
			if(watchedServers.size() == 0)
			{
				buf.close();
			
				bufServerMap.remove(buf.getBufID());
				resBufMap.remove(resType);
				if(resBufMap.size() == 0)
					watchBufMap.remove(wID);
			}
		}
		
		return deWatch;
	}
	
	public static void notifyBuf(List<DataMsg> data, ResourceType resType, Identity wID)
	{
		Map<ResourceType, WatchBuffer> resBufMap = watchBufMap.get(wID);
		if(resBufMap == null)
		{
			System.err.println("Watch notification from server not watched");
			return;
		}
		WatchBuffer buf = resBufMap.get(resType);
		if(buf == null)
		{
			System.err.println("Watch notification from server not watched");
			return;
		}
		buf.write(data);
	}
	
	public static WatchBuffer getBuffer(ResourceType resType, Identity wID)
	{
		Map<ResourceType, WatchBuffer> resBufMap = watchBufMap.get(wID);
		if(resBufMap == null)
			return null;
		
		return resBufMap.get(resType);
	}
	
	public static void close()
	{
		//todo
	}
}
